/**
@file this demo is aimed to demostrate OCP.
@author jimmyzhangcdcn@outlook.com
*/

#include <string>
#include <iostream>
#include <list>
using namespace std;

class ApiStat
{
private:
	unsigned int m_tp;
	unsigned int m_err;
	unsigned int m_duration;

	ApiStat(const ApiStat &);
	ApiStat& operator=(const ApiStat &);
public:
	unsigned int get_tp() const {return m_tp;};
	unsigned int get_err() const {return m_err;};
	unsigned int get_duration() const {return m_duration;};
	ApiStat(unsigned int tp, unsigned int err, unsigned int duration):m_tp(tp), m_err(err), m_duration(duration){};
};

class Rule
{
private:
	unsigned int m_max_tps;
	unsigned int m_max_errs;
public:
	unsigned int get_max_tps() const {return m_max_tps;};
	unsigned int get_max_errs() const {return m_max_errs;};
	Rule(unsigned int max_tps, unsigned int max_errs):m_max_tps(max_tps), m_max_errs(max_errs){};
	Rule(const Rule &) = delete;
	Rule& operator=(const Rule &) = delete;
};

class Notification
{
public:
	bool notify(const string &msg)
	{
		cout << msg << endl;
	};
};

class AlertHandler
{
protected:
	Rule *m_p_rule;
	Notification *m_p_notification;
public:
	AlertHandler(Rule *p_rule, Notification *p_notification):\
			m_p_rule(p_rule),m_p_notification(p_notification)
			{};
	virtual bool check(const ApiStat& stat) = 0;
};

class TpsAlertHandler : public AlertHandler
{
public:
	virtual bool check(const ApiStat &stat)
	{
		if (stat.get_tp()/stat.get_duration() > m_p_rule->get_max_tps())
		{
			m_p_notification->notify("tps warning");
		}
	}
	TpsAlertHandler(Rule *p_rule, Notification *p_notification): AlertHandler(p_rule, p_notification){};
};

class MaxerrAlertHandler : public AlertHandler
{
public:
	virtual bool check(const ApiStat &stat)
	{
		if (stat.get_err()/stat.get_duration() > m_p_rule->get_max_errs())
		{
			m_p_notification->notify("max errs warning");
		}
	}
	MaxerrAlertHandler(Rule *p_rule, Notification *p_notification): AlertHandler(p_rule, p_notification){};
};

class Alert
{
private:
	list<AlertHandler *> m_handlers;	
public:
	void AddHandler(AlertHandler *p_handler)
	{
		m_handlers.push_back(p_handler);
	}
	void ClearAllHandler()
	{
		for (auto & handler : m_handlers)
		{
			delete handler;
		}
	}
	void Check(const ApiStat &stat)
	{
		for (auto &handler : m_handlers)
		{
			handler->check(stat);
		}
	}
};


int main(int argc, const char *argv[])
{
	Rule *p_rule = new Rule(200, 200);
	Notification *p_notification = new Notification();

	Alert alert;
	alert.AddHandler(new TpsAlertHandler(p_rule, p_notification));
	alert.AddHandler(new MaxerrAlertHandler(p_rule, p_notification));
	ApiStat s1(2001, 3000, 10);
	ApiStat s2(10000, 3000, 10);
	alert.Check(s1);
	alert.Check(s2);
	alert.ClearAllHandler();

	delete p_rule;
	delete p_notification;

	return 0;
}
